#pragma once

#include <cstdint>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <string>
#include <vector>

class PostgresqlResultSetParser {
  public:
    enum class ParseStatus { COMPLETE, INCOMPLETE, TRUNCATED, MALFORMED };

    struct ColumnInfo {
        std::string name;
        std::string type;
        uint32_t table_oid;
    };

    ParseStatus parse(const std::vector<uint8_t> &packet) {
        size_t pos = 0;

        if (packet.empty())
            return ParseStatus::MALFORMED;
        if (packet[0] != 'T')
            return ParseStatus::MALFORMED; // RowDescription 标识符

        pos = 1;
        if (pos + 4 > packet.size())
            return ParseStatus::TRUNCATED;

        uint32_t len = read_uint32(packet, pos); // 包长度（包含自身长度）
        if (pos + len - 4 > packet.size())
            return ParseStatus::TRUNCATED;

        return parse_result_set(packet, pos);
    }

    std::vector<uint32_t> getTableOids() const {
        std::vector<uint32_t> oids;
        for (const auto &col : columns) {
            oids.push_back(col.table_oid);
        }
        return oids;
    }
    uint32_t getFirstTableOid() const { return !columns.empty() ? columns[0].table_oid : 0; }
    size_t getColumnCount() const { return column_count; }
    const std::vector<ColumnInfo> &getColumns() const { return columns; }

  private:
    size_t column_count = 0;
    std::vector<ColumnInfo> columns;

    ParseStatus parse_result_set(const std::vector<uint8_t> &packet, size_t &pos) {
        if (pos + 2 > packet.size())
            return ParseStatus::TRUNCATED;

        column_count = read_uint16(packet, pos);
        columns.clear();

        for (size_t i = 0; i < column_count; ++i) {
            // 1. 字段名（以 \0 结尾的字符串）
            std::string col_name;
            while (pos < packet.size() && packet[pos] != '\0') {
                col_name.push_back(packet[pos++]);
            }
            if (pos >= packet.size())
                return ParseStatus::TRUNCATED;
            ++pos; // skip null terminator

            // 2. table_oid (4字节)
            if (pos + 4 > packet.size())
                return ParseStatus::TRUNCATED;
            uint32_t table_oid = read_uint32(packet, pos);

            // 3. 列号（2字节） - 可忽略
            pos += 2;

            // 4. 类型OID（4字节）
            if (pos + 4 > packet.size())
                return ParseStatus::TRUNCATED;
            uint32_t type_oid = read_uint32(packet, pos);

            // 5. 类型长度（2字节）
            pos += 2;

            // 6. 类型修饰符（4字节）
            pos += 4;

            // 7. 格式代码（2字节）
            pos += 2;

            columns.push_back({col_name, postgresql_type_to_string(type_oid), table_oid});
        }

        return ParseStatus::COMPLETE;
    }

    // 工具函数
    uint16_t read_uint16(const std::vector<uint8_t> &packet, size_t &pos) {
        uint16_t val = (packet[pos] << 8) | packet[pos + 1];
        pos += 2;
        return val;
    }

    uint32_t read_uint32(const std::vector<uint8_t> &packet, size_t &pos) {
        uint32_t val = (packet[pos] << 24) | (packet[pos + 1] << 16) | (packet[pos + 2] << 8) | packet[pos + 3];
        pos += 4;
        return val;
    }

    std::string postgresql_type_to_string(uint32_t oid) {
        switch (oid) {
        case 16:
            return "bool";
        case 17:
            return "bytea";
        case 18:
            return "char";
        case 19:
            return "name";
        case 20:
            return "int8";
        case 21:
            return "int2";
        case 23:
            return "int4";
        case 25:
            return "text";
        case 700:
            return "float4";
        case 701:
            return "float8";
        case 1042:
            return "char";
        case 1043:
            return "varchar";
        case 1082:
            return "date";
        case 1114:
            return "timestamp";
        case 1184:
            return "timestamptz";
        case 1700:
            return "numeric";
        default:
            return "unknown(" + std::to_string(oid) + ")";
        }
    }

    void dump_hex(const std::vector<uint8_t> &data, size_t start_pos) {
        for (size_t i = start_pos; i < data.size(); ++i) {
            std::cout << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(data[i]) << " ";
            if ((i - start_pos) % 16 == 15)
                std::cout << std::endl;
        }
        std::cout << std::dec << std::endl;
    }
};
